const fs = require("fs");
const splitFile = require("split-file");
const mkdirp = require('mkdirp-promise');
const path = require("path");
const moveFile = require("move-file");
const listFilepaths = require('list-filepaths');


/**
 * 
 * @param {String} full_path 
 * @returns {Promise<Boolean>}
 */
function checkExists(full_path) {
  return new Promise(r => fs.exists(full_path, $ => r($)))
}

/**
 * 
 * @param {String} full_path 
 * @returns {Promise<Boolean>}
 */
function checkIsFile(full_path) {
  return new Promise(r => fs.stat(full_path, (err, stats) => {
    if (err) {
      return r(false);
    } else {
      return r(stats.isFile());
    }
  }))
}

/**
 * 
 * @param {String} full_path 
 * @returns {Promise<Boolean>}
 */
function checkIsDir(full_path) {
  return new Promise(r => fs.stat(full_path, (err, stats) => {
    if (err) {
      return r(false);
    } else {
      return r(stats.isDirectory());
    }
  }))
}

/**
 * @description You'd better check if it exists and it is a file
 * @param {String} full_path 
 * @returns {Promise<{result:Boolean,size:Number,message:String}>}
 */
function checkFileSize(full_path) {
  return new Promise(r => fs.stat(full_path, (err, stats) => {
    if (err) {
      return r({
        result: false,
        message: err.message,
        size: Infinity
      })
    } else {
      let size = stats.size;
      r({
        result: true,
        size: size,
        message: "ok"
      })
    }
  }))
}

/**
 * @description You'd better check if it exists and it is a file
 * @param {String} full_path 
 * @param {Number} maxSize 
 * @returns {Promise<{result:Boolean,splitted_files:String[],message:String}>}
 */
function splitFileBySize(full_path, maxSize) {
  return new Promise(r => splitFile.splitFileBySize(full_path, maxSize)
    .then(file_paths => r({
      result: true,
      splitted_files: file_paths,
      message: "OK"
    }))
    .catch(err => {
      r({
        result: false,
        splitted_files: [],
        message: err.message ? err.message : String(err)
      })
    }))
}


/**
 * @description You'd better check if it exists and it is a file
 * @param {String} full_path 
 * @param {Number} maxSize 
 * @param {String} target_dir_path the dir path for splitted files to store 
 * @returns {Promise<{result:Boolean,splitted_files:String[],message:String}>}
 */
function splitFileBySizeAndMove(full_path, maxSize, target_dir_path = null) {
  return new Promise(async resolve => {
    if (target_dir_path) {
      let o_exists = await checkExists(target_dir_path);
      if (!o_exists) {
        //新建该目录
        try {
          await mkdirp(target_dir_path)
        } catch (error) {
          return resolve({
            result: false,
            splitted_files: [],
            message: `Error when try mkdirp (${target_dir_path}) : ${(error&&error.message)?error.message:error}`
          })
        }
      } else {
        let o_isDir = await checkIsDir(target_dir_path);
        if (!o_isDir) {
          return resolve({
            result: false,
            splitted_files: [],
            message: `the path (${target_dir_path}) exists but is not a dir`
          })
        }
      }
    }

    let o_split = await splitFileBySize(full_path, maxSize);
    if ((!o_split.result) || (!target_dir_path)) {
      return resolve({
        result: o_split.result,
        splitted_files: o_split.splitted_files,
        message: o_split.message
      });
    }
    if (target_dir_path) {
      let p_moves = Promise.all(o_split.splitted_files.map(
        /**
         * @returns {Promise<String>}
         */
        origin_path => new Promise(async (rslv, rjct) => {
          let dest_path = path.join(target_dir_path, path.basename(origin_path));
          try {
            await moveFile(origin_path, dest_path);
            rslv(dest_path);
          } catch (error) {
            rjct(error);
          }
        })));
      p_moves.then(dest_paths => {
        resolve({
          result: true,
          splitted_files: dest_paths,
          message: "ok"
        })
      }).catch(error => {
        resolve({
          resolve: false,
          splitted_files: [],
          message: `Error when moving : ${error}`
        })
      });
    }
  })
}

/**
 * @description 返回某个路径下的所有文件的绝对路径;执行前务必确认dir_full_path确实指向一个文件夹
 * @returns {Promise<{result:Boolean,message:String,listed_files:[]}>}
 * @param {String} dir_full_path 
 * @param {{depth:Number,filter:RegExp|function(p:string):boolean,reject:RegExp|function(p:string)}} options 
 */
function listDirFiles(dir_full_path, options) {
  return new Promise(async resolve => {
    listFilepaths(dir_full_path, options)
      .then(file_paths => resolve({
        result: true,
        message: 'ok',
        listed_files: file_paths
      }))
      .catch(error =>
        resolve({
          result: false,
          message: (error && error.message) ? error.message : String(error),
          listed_files:[]
        })
      )
  })
}


module.exports = {
  checkExists: checkExists,
  checkIsFile: checkIsFile,
  checkIsDir: checkIsDir,
  checkFileSize: checkFileSize,
  splitFileBySize: splitFileBySize,
  splitFileBySizeAndMove: splitFileBySizeAndMove,
  listDirFiles
}